/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.hamacekj.dotaznikklient;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * Hlavní vlákno aplikace. Poslouchá na nastaveném portu, zpracovává příkazy protokolu, 
 * třídí je podle typu a předává řízení do implementací abstraktu {@link Question Question}.
 * @author Jan Hamáček
 */
public class DotaznikKlient {
    
    static private Socket socket;
    static private QuestionsQueue questions;
    
    /**
     * Volá listen(int) s parametrem 7475
     */
    private static void listen(){
        listen(7475);
    }
    
    /**
     * Vytvoří server, poslouchá na portu a zpracovává všechny požadavky.
     * @param port číslo portu, na kterém bude poslouchat.
     */
    private static void listen(int port){
        try{
            try (ServerSocket s = new ServerSocket(port)) {
                while(true){
                    socket = s.accept();
                    try{
                        BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                socket.getInputStream(), charset));
                        BufferedWriter out = new BufferedWriter(
                                new OutputStreamWriter(
                                socket.getOutputStream(), charset));
                        while(processInput(in, out)){}

                    }catch(IOException e){
                        socket.close();
                    }
                }
            }
        }catch(IOException e){
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    JOptionPane.showMessageDialog(null, "Nepodařilo se začít naslouchat na portu 7475, program bude ukončen.", "Chyba při spouštění", JOptionPane.ERROR_MESSAGE);
                    System.exit(1);
                }
            });
        }
    }
    
    /**
     * Čte ze vstupního proudu, zpracuje jeden příkaz. Pro každý příkaz 
     * se rozhodne o jaký typ příkazu jde a předá řízení jedné z implementací
     * abstraktu {@link Question Question}.
     * @param in Vstupní proud
     * @param out Výstupní proud. Do něj se zapisují odpovědi.
     * @returns true pokud v průběhu čtení neskončil proud a má tedy smysl číst dál. false jinak
     * @throws IOException Chyba při čtení/zápisu.
     */
    private static boolean processInput(BufferedReader in, BufferedWriter out) throws IOException{
        try{
            String firstLine = in.readLine();
            if(firstLine == null){
                return false;
            }
            String[] firstLineSplit = firstLine.split(" ", 3);
            if("ASK".equals(firstLineSplit[0])){
                Question q = null;
                switch(firstLineSplit[1]){
                    case "YN":
                        q = new YNQuestion(out, questions);
                        q.fromFirstLine(firstLine);
                        loadData(in, q);
                        questions.add(q);
                        break;
                    case "TEXT":
                        q = new TextQuestion(out, questions);
                        q.fromFirstLine(firstLine);
                        loadData(in, q);
                        questions.add(q);
                        break;
                    case "RADIO":
                        q = new RadioQuestion(out, questions);
                        q.fromFirstLine(firstLine);
                        loadData(in, q);
                        questions.add(q);
                        break;
                    case "NAME":
                        q = new NameQuestion(out, questions);
                        q.fromFirstLine(firstLine);
                        questions.add(q);
                    default:
                        throw new ProtocolException();
                }
            }
            if("STOP".equals(firstLineSplit[0])){
                questions.cancel();
                return true;
            }
        }catch(ProtocolException ex){
            out.write("ERROR 400 Chyba protokolu. Nerozpoznany prikaz.");
            out.newLine();
            out.flush();
            return true;
        }
        return true;
    }
    
    private static void loadData(BufferedReader in, Question q) throws IOException, ProtocolException{
        String line = in.readLine();
        while(line != null && !".".equals(line)){
            q.addParam(line);
            line = in.readLine();
        }
    }
    
    
    /**
     * Start programu. Parsuje argumenty a spouští naslouchání v síti.
     * @param args první volitelný argument je číslo portu, na kterém se bude
     * naslouchat žádné další argumenty neexistují.
     */
    public static void main(String[] args) {
        int port = 7475;
        try{
            if(args.length > 0){
                port = Integer.parseInt(args[0]);
            }
        }catch(IndexOutOfBoundsException | NumberFormatException e){
        }
        try{
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }catch(Exception e){}
        questions = new QuestionsQueue();
        listen(port);
    }
    
    /** Znaková sada použitá k síťovému přenosu. Musí být stejná na serveru i na klientovi */
    private static final Charset charset = Charset.forName("UTF-8");
}
